Alejandro Betancur Quiroz
Se cuenta con información del número de registros diarios de vehículos en el Registro Único Nacional de Tránsito (RUNT). Se desea construir un modelo de aprendizaje que pueda realizar predicciones para esta variable llamada a partir de ahora value. El modelo no podrá incurrir en overffiting por lo que la diferencia entre el coeficiente de determinación del periodo de entrenamiento y el periodo de prueba no podrá ser mayor al 10%.
Respecto a las variables explicativas, estas deberán ser independientes a value por lo que no se podrán construir modelos autoregresivos o basados en rezagos de esta variable. Las variables escogidas se discuten en una sección posterior.
Corresponde a la variable que se desea predecir (value), en este caso la cantidad de registros en el RUNT.
Como puede notarse en la siguiente gráfica, los datos tienen un ciclo semanal y un ciclo anual. Debido a esto se presentan el mayor número de registro entre los días martes y viernes. Además, se presentan también un mayor número de registros a final de año.
Cabe destacar que los registros presentan una diferencia en la media, tal como se nota en la gráfica anterior y también al realizar un agrupamiento por semana (siguiente figura).
Como se resaltó anteriormente los datos presentan diferentes periodicidades, por lo que esta característica se tomará en cuento realizando una descomposición en términos de senos y cosenos el día de la semana, el número de la semana y el mes.
En las siguientes gráficas se representan coseno Vs. seno de cada una de estas variables, donde el tamaño representa la cantidad media
Empleando el paquete holidays_co de Python se construyó la variable holiday la cual toma el valor de 1 si la fecha correspondiente es un día festivo y 0 en caso contrario. Así mismo, al partir de esta variable se construyeron también las variables day_before_holiday y week_with_holiday. La primera toma el valor de 1 si el día anterior fue un día festivo (0 en caso contrario) y la segunda toma el valor de 1 si en la semana a la cual pertenece el día hubo un día festivo (0 en caso contrario).
| holiday | day_before_holiday | week_with_holiday | |
|---|---|---|---|
| 2012-01-01 | 1.000 | 0.000 | 1.000 |
| 2012-01-02 | 0.000 | 1.000 | 0.000 |
| 2012-01-03 | 0.000 | 0.000 | 0.000 |
| 2012-01-04 | 0.000 | 0.000 | 0.000 |
| 2012-01-05 | 0.000 | 0.000 | 0.000 |
| 2012-01-06 | 0.000 | 0.000 | 0.000 |
| 2012-01-07 | 0.000 | 0.000 | 0.000 |
| 2012-01-08 | 0.000 | 0.000 | 0.000 |
| 2012-01-09 | 1.000 | 0.000 | 1.000 |
| 2012-01-10 | 0.000 | 1.000 | 1.000 |
| 2012-01-11 | 0.000 | 0.000 | 1.000 |
| 2012-01-12 | 0.000 | 0.000 | 1.000 |
| 2012-01-13 | 0.000 | 0.000 | 1.000 |
| 2012-01-14 | 0.000 | 0.000 | 1.000 |
La información del histórico de la Tasa Representativa del Mercado (TRM) del Dólar en Colombia se obtuvo de la página de Datos Abiertos del Gobierno de Colombia (link de descarga).
A partir de un correlograma entre la variable trm y valuese determinaron rezagos de la TRM con importancia para ser incluidos en el modelo. A continuación se presenta dicho correlograma y la serie histórica de la TRM.
Empleando el paquete pytrends se obtienen los registros de busqueda en Colombia de las palabras carro, moto y RUNT en Google. Y al igual que para la TRM se utiliza una estrategia de correlaciones rezagadas con value para seleccionar rezagos con importancia.
Las series de estas variables se presentan a continuación:
El conjunto de datos final derivado de las variables previamente mencionadas tiene esta forma:
| value | cos_month | sin_month | cos_n_week | sin_n_week | cos_weekday | sin_weekday | holiday | day_before_holiday | week_with_holiday | trm_shift_45 | trm_shift_60 | trm_shift_404 | trm_shift_592 | gt_carro | gt_moto | gt_RUNT | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2012-01-01 | 0.000 | 0.866 | 0.500 | 1.000 | 0.000 | 0.623 | -0.782 | 1.000 | 0.000 | 1.000 | 1913.694 | 1870.427 | 1875.821 | 1967.834 | 468.000 | 339.000 | 148.000 |
| 2012-01-02 | 188.000 | 0.866 | 0.500 | 0.993 | 0.121 | 1.000 | 0.000 | 0.000 | 1.000 | 0.000 | 1913.291 | 1872.079 | 1877.516 | 1972.224 | 557.000 | 297.000 | 125.000 |
| 2012-01-03 | 482.000 | 0.866 | 0.500 | 0.993 | 0.121 | 0.623 | 0.782 | 0.000 | 0.000 | 0.000 | 1913.834 | 1878.156 | 1879.420 | 1980.519 | 344.000 | 266.000 | 371.000 |
| 2012-01-04 | 927.000 | 0.866 | 0.500 | 0.993 | 0.121 | -0.223 | 0.975 | 0.000 | 0.000 | 0.000 | 1914.377 | 1885.679 | 1882.747 | 1984.850 | 516.000 | 327.000 | 296.000 |
| 2012-01-05 | 1159.000 | 0.866 | 0.500 | 0.993 | 0.121 | -0.901 | 0.434 | 0.000 | 0.000 | 0.000 | 1914.920 | 1893.201 | 1887.219 | 1989.181 | 323.000 | 367.000 | 408.000 |
Dada la correlación entre las diferentes variables (gráfica anterior) se toma la decisión de procesar las variables de entrada empleando PCA. Sin embargo, antes de esto las variables se escalan para evitar los efectos de la diferencia de magnitud entre las diferentes variables.
A continuación, se muestran las componentes pricipales y la varianza explicada por cada componente principal.
Los modelos se entrenaron en un esquema de validación cruzada temporal (TimeSeriesSplit de Sklearn) en el periodo de entrenamiento. La siguiente figura esquematiza dicho esquema y fue tomada de la documentación de la función en Sklearn.
.png)
Además, se seleccionaron los mejores hiperparámetros mediante GridSearchCV de Sklearn empleando el MSE como métrica de evaluación. Además, cabe destacar que también se realizó tuning del número de componentes principales empleadas para el pronóstico.
A continuación, se presentan los diferentes hiper- parámetros probados junto con el mejor conjunto de entrenamiento para cada uno de los modelos evaluados. Sumado a esto, se realizó un análisis de importancia de variables de los modelos entrenados empleando permutation_importance` de Sklearn y usando RMSE como métrica de evaluación, estos resultados también se presentan para cada modelo.
Los hiperpárametros empleados fueron: {'estimator__alpha': np.logspace(-4, 6, 100)}
Los mejores hiperpárametros encontrados son: {'estimatoralpha': 1.747528400007683, 'pcan_components': 13}
El gráfico cuantil-cuantil de este modelo para ambos peridos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.054 | 0.007 | sin_weekday |
| 4 | 0.024 | 0.003 | cos_weekday |
| 6 | 0.014 | 0.003 | holiday |
| 7 | 0.001 | 0.001 | day_before_holiday |
| 8 | 0.001 | 0.000 | week_with_holiday |
| 11 | -0.000 | 0.000 | trm_shift_404 |
| 0 | -0.000 | 0.000 | cos_month |
| 3 | -0.000 | 0.000 | sin_n_week |
| 12 | -0.000 | 0.000 | trm_shift_592 |
| 13 | -0.000 | 0.000 | gt_carro |
| 1 | -0.000 | 0.000 | sin_month |
| 2 | -0.000 | 0.000 | cos_n_week |
| 9 | -0.000 | 0.000 | trm_shift_45 |
| 10 | -0.000 | 0.000 | trm_shift_60 |
| 15 | -0.001 | 0.000 | gt_RUNT |
| 14 | -0.001 | 0.000 | gt_moto |
Los hiperpárametros empleados fueron: {'estimator__alpha': np.logspace(-4, 6, 100)}
Los mejores hiperpárametros encontrados son: {'estimatoralpha': 1.747528400007683, 'pcan_components': 13}
El gráfico cuantil-cuantil de este modelo para ambos periodos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.054 | 0.007 | sin_weekday |
| 4 | 0.024 | 0.003 | cos_weekday |
| 6 | 0.014 | 0.003 | holiday |
| 7 | 0.001 | 0.001 | day_before_holiday |
| 8 | 0.001 | 0.000 | week_with_holiday |
| 11 | -0.000 | 0.000 | trm_shift_404 |
| 0 | -0.000 | 0.000 | cos_month |
| 3 | -0.000 | 0.000 | sin_n_week |
| 12 | -0.000 | 0.000 | trm_shift_592 |
| 13 | -0.000 | 0.000 | gt_carro |
| 1 | -0.000 | 0.000 | sin_month |
| 2 | -0.000 | 0.000 | cos_n_week |
| 9 | -0.000 | 0.000 | trm_shift_45 |
| 10 | -0.000 | 0.000 | trm_shift_60 |
| 15 | -0.001 | 0.000 | gt_RUNT |
| 14 | -0.001 | 0.000 | gt_moto |
Los hiperpárametros empleados fueron: {'estimator__alpha': np.logspace(-4, 6, 100)}
Los mejores hiperpárametros encontrados son: {'estimatoralpha': 0.001788649529057435, 'pcan_components': 13}
El gráfico cuantil-cuantil de este modelo para ambos periodos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.051 | 0.006 | sin_weekday |
| 4 | 0.022 | 0.003 | cos_weekday |
| 6 | 0.010 | 0.002 | holiday |
| 8 | 0.001 | 0.000 | week_with_holiday |
| 15 | 0.001 | 0.000 | gt_RUNT |
| 7 | 0.001 | 0.001 | day_before_holiday |
| 13 | 0.000 | 0.000 | gt_carro |
| 14 | 0.000 | 0.000 | gt_moto |
| 12 | 0.000 | 0.000 | trm_shift_592 |
| 11 | -0.000 | 0.000 | trm_shift_404 |
| 0 | -0.000 | 0.000 | cos_month |
| 3 | -0.000 | 0.000 | sin_n_week |
| 1 | -0.000 | 0.000 | sin_month |
| 2 | -0.000 | 0.000 | cos_n_week |
| 9 | -0.000 | 0.000 | trm_shift_45 |
| 10 | -0.000 | 0.000 | trm_shift_60 |
Los hiperpárametros empleados fueron: { 'estimatorn_neighbors': range(3, 30), 'estimatorweights': ['uniform','distance'], 'estimator__p': [1, 2, 3], }
Los mejores hiperpárametros encontrados son:
{'estimatorn_neighbors': 7, 'estimatorp': 1, 'estimatorweights': 'distance', 'pcan_components': 10}
El gráfico cuantil-cuantil de este modelo para ambos periodos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.064 | 0.008 | sin_weekday |
| 4 | 0.050 | 0.005 | cos_weekday |
| 14 | 0.018 | 0.002 | gt_moto |
| 15 | 0.014 | 0.003 | gt_RUNT |
| 13 | 0.013 | 0.003 | gt_carro |
| 3 | 0.011 | 0.003 | sin_n_week |
| 1 | 0.011 | 0.003 | sin_month |
| 0 | 0.008 | 0.003 | cos_month |
| 10 | 0.008 | 0.002 | trm_shift_60 |
| 2 | 0.008 | 0.002 | cos_n_week |
| 11 | 0.007 | 0.001 | trm_shift_404 |
| 8 | 0.007 | 0.004 | week_with_holiday |
| 6 | 0.006 | 0.005 | holiday |
| 9 | 0.006 | 0.002 | trm_shift_45 |
| 12 | 0.006 | 0.002 | trm_shift_592 |
| 7 | 0.002 | 0.001 | day_before_holiday |
Los hiperpárametros empleados fueron: { 'estimatormax_features' : [1, 'sqrt', 'log2'], 'estimatorn_estimators': [400], 'estimator__max_depth': [3, 4, 5], }
Los mejores hiperpárametros encontrados son: {'estimatormax_depth': 5, 'estimatormax_features': 'sqrt', 'estimatorn_estimators': 400, 'pcan_components': 9}
El gráfico cuantil-cuantil de este modelo para ambos periodos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.074 | 0.007 | sin_weekday |
| 4 | 0.024 | 0.002 | cos_weekday |
| 6 | 0.020 | 0.004 | holiday |
| 7 | 0.006 | 0.002 | day_before_holiday |
| 8 | 0.005 | 0.001 | week_with_holiday |
| 3 | 0.001 | 0.000 | sin_n_week |
| 13 | 0.001 | 0.001 | gt_carro |
| 1 | 0.000 | 0.000 | sin_month |
| 14 | 0.000 | 0.000 | gt_moto |
| 9 | 0.000 | 0.000 | trm_shift_45 |
| 10 | 0.000 | 0.000 | trm_shift_60 |
| 15 | 0.000 | 0.001 | gt_RUNT |
| 11 | 0.000 | 0.000 | trm_shift_404 |
| 12 | -0.000 | 0.000 | trm_shift_592 |
| 2 | -0.001 | 0.000 | cos_n_week |
| 0 | -0.001 | 0.000 | cos_month |
Los hiperpárametros empleados fueron:
{ 'estimatormax_features' : [1, 'sqrt', 'log2'], 'estimatormax_depth' : [1, 3, 5], 'estimatorsubsample' : [0.5, 1], 'estimatorlearning_rate' : [0.001, 0.01, 0.1], }
Los mejores hiperpárametros encontrados son:
{'estimatorlearning_rate': 0.1, 'estimatormax_depth': 5, 'estimatormax_features': 'sqrt', 'estimatorsubsample': 1, 'pca__n_components': 9}
El gráfico cuantil-cuantil de este modelo para ambos periodos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.080 | 0.008 | sin_weekday |
| 4 | 0.043 | 0.004 | cos_weekday |
| 6 | 0.019 | 0.004 | holiday |
| 8 | 0.005 | 0.002 | week_with_holiday |
| 14 | 0.004 | 0.001 | gt_moto |
| 15 | 0.004 | 0.002 | gt_RUNT |
| 13 | 0.004 | 0.001 | gt_carro |
| 7 | 0.003 | 0.002 | day_before_holiday |
| 3 | 0.003 | 0.002 | sin_n_week |
| 1 | 0.001 | 0.002 | sin_month |
| 11 | 0.001 | 0.001 | trm_shift_404 |
| 10 | 0.001 | 0.001 | trm_shift_60 |
| 9 | 0.001 | 0.001 | trm_shift_45 |
| 12 | 0.000 | 0.001 | trm_shift_592 |
| 2 | -0.009 | 0.003 | cos_n_week |
| 0 | -0.009 | 0.003 | cos_month |
Los hiperpárametros empleados fueron:
{ 'estimatorC': [10, 50, 75], 'estimatorgamma': [0.1, 0.01, 0.001, 0.0001], 'estimator__kernel': ['rbf', 'poly', 'sigmoid', 'linear'] }
Los mejores hiperpárametros encontrados son:
{'estimatorC': 75, 'estimatorgamma': 0.01, 'estimatorkernel': 'rbf', 'pcan_components': 12}
El gráfico cuantil-cuantil de este modelo para ambos periodos es:

Así mismo, los resultados de análisis de importancia empleando permutación es:
| importances_mean | importances_std | feature | |
|---|---|---|---|
| 5 | 0.059 | 0.006 | sin_weekday |
| 4 | 0.034 | 0.004 | cos_weekday |
| 6 | 0.019 | 0.004 | holiday |
| 15 | 0.002 | 0.000 | gt_RUNT |
| 11 | 0.000 | 0.000 | trm_shift_404 |
| 12 | 0.000 | 0.000 | trm_shift_592 |
| 13 | -0.000 | 0.000 | gt_carro |
| 0 | -0.000 | 0.000 | cos_month |
| 7 | -0.000 | 0.001 | day_before_holiday |
| 14 | -0.000 | 0.000 | gt_moto |
| 2 | -0.000 | 0.000 | cos_n_week |
| 3 | -0.001 | 0.000 | sin_n_week |
| 9 | -0.001 | 0.000 | trm_shift_45 |
| 10 | -0.001 | 0.000 | trm_shift_60 |
| 8 | -0.001 | 0.001 | week_with_holiday |
| 1 | -0.001 | 0.000 | sin_month |
Finalmente, se presentan diferentes métricas para los diferentes modelos evaluados.
| r2 | explained_variance | max_error | mean_absolute_error | mean_squared_error | root_mean_squared_error | ||
|---|---|---|---|---|---|---|---|
| model | period | ||||||
| Ridge | train | 0.647 | 0.648 | 2428.417 | 242.827 | 105886.117 | 325.401 |
| val | 0.467 | 0.467 | 2310.263 | 249.687 | 148869.585 | 385.836 | |
| Lasso | train | 0.639 | 0.641 | 2399.894 | 244.855 | 108366.020 | 329.190 |
| val | 0.437 | 0.479 | 2193.583 | 287.991 | 157321.248 | 396.637 | |
| ElasticNet | train | 0.637 | 0.639 | 2433.498 | 245.922 | 108874.980 | 329.962 |
| val | 0.467 | 0.481 | 2268.861 | 269.624 | 148749.713 | 385.681 | |
| KNeighborsRegressor | train | 0.999 | 1.000 | 111.000 | 13.772 | 278.745 | 16.696 |
| val | 0.520 | 0.529 | 2079.989 | 221.881 | 134090.793 | 366.184 | |
| RandomForestRegressor | train | 0.829 | 0.830 | 1678.254 | 148.835 | 51354.882 | 226.616 |
| val | 0.562 | 0.595 | 2028.936 | 235.480 | 122287.797 | 349.697 | |
| GradientBoostingRegressor | train | 0.920 | 0.921 | 983.551 | 97.834 | 23938.311 | 154.720 |
| val | 0.543 | 0.544 | 2168.320 | 202.135 | 127604.762 | 357.218 | |
| SVR | train | 0.781 | 0.781 | 2277.778 | 173.373 | 65638.486 | 256.200 |
| val | 0.493 | 0.538 | 2214.409 | 263.561 | 141638.335 | 376.349 |
Dado lo anterior, el modelo escogido es RandomForestRegressor debido a que es el que tienen desempeño en diferentes métricas en el periodo de validación.